﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using System.Net;

namespace net.xBei.Helper;
/// <summary>
/// 
/// </summary>
public static class UriHelper {
    /// <summary>
    /// 设置<see cref="Uri.AbsolutePath"/>
    /// </summary>
    /// <param name="uri"></param>
    /// <param name="newPath"></param>
    /// <returns></returns>
    public static Uri SetPath(this Uri uri, string newPath)
        => new UriBuilder(uri) {
            Path = newPath,
        }.Uri;
    /// <summary>
    /// 
    /// </summary>
    /// <param name="uri"></param>
    /// <returns></returns>
    public static Uri ClearQuery(this Uri uri) {
        var builder = new UriBuilder(uri) {
            Query = string.Empty
        };
        return builder.Uri;
    }
    /// <summary>
    /// 设置QueryString，会返回一个新的Uri对象
    /// </summary>
    /// <param name="uri"></param>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static Uri AddQuery(this Uri uri, string key, string value) {
        var builder = new UriBuilder(uri) {
            Query = AddQuery(QueryString.FromUriComponent(uri), key, value).ToString()
        };
        return builder.Uri;
    }
    /// <summary>
    /// 设置QueryString，会返回一个新的Uri对象
    /// </summary>
    /// <param name="uri"></param>
    /// <param name="dict"></param>
    /// <returns></returns>
    public static Uri AddQuery(this Uri uri, IDictionary<string, string> dict) {
        var builder = new UriBuilder(uri) {
            Query = AddQuery(QueryString.FromUriComponent(uri), dict).ToString()
        };
        return builder.Uri;
    }
    /// <summary>
    /// 设置QueryString，修改UriBuilder
    /// </summary>
    /// <param name="builder"></param>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static UriBuilder AddQuery(this UriBuilder builder, string key, string value) {
        var qs = AddQuery(QueryString.FromUriComponent(builder.Uri), key, value);
        builder.Query = qs.ToString();
        return builder;
    }
    /// <summary>
    /// 设置QueryString，修改UriBuilder
    /// </summary>
    /// <param name="builder"></param>
    /// <param name="dict"></param>
    /// <returns></returns>
    public static UriBuilder AddQuery(this UriBuilder builder, IDictionary<string, string> dict) {
        builder.Query = AddQuery(QueryString.FromUriComponent(builder.Uri), dict).ToString();
        return builder;
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="qs"></param>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static QueryString AddQuery(this QueryString qs, string key, string value) {
        qs += QueryString.Create(key, value);
        return qs;
    }
    #region SET QUERY
    /// <summary>
    /// 
    /// </summary>
    /// <param name="uriStr"></param>
    /// <param name="query"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public static string SetQuery(this string uriStr, IEnumerable<KeyValuePair<string, string>> query)
        => Uri.TryCreate(uriStr, UriKind.RelativeOrAbsolute, out var uri) && uri.IsAbsoluteUri
            ? SetQuery(uri, query).AbsoluteUri
            : throw new ArgumentException("无效的地址", nameof(uriStr));
    /// <summary>
    /// 设置地址的查询条件（“?”以后的）
    /// </summary>
    /// <param name="uri"></param>
    /// <param name="query">如果存在相同的 key 会覆盖</param>
    /// <returns></returns>
    public static Uri SetQuery(this Uri uri, IEnumerable<KeyValuePair<string, string>> query) {
        var qc = GetQuery(uri).SetQuery(query);
        var builder = new UriBuilder(uri) {
            Query = QueryString.Create(qc).ToString(),
        };
        return builder.Uri;
    }
    /// <summary>
    /// 设置地址的查询条件（“?”以后的）
    /// </summary>
    /// <param name="uri"></param>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static Uri SetQuery(this Uri uri, string key, string value) {
        var qc = GetQuery(uri).SetQuery(key, value);
        var builder = new UriBuilder(uri) {
            Query = QueryString.Create(qc).ToString(),
        };
        return builder.Uri;
    }
    /// <summary>
    /// 设置地址的查询条件（“?”以后的）
    /// </summary>
    /// <param name="uri"></param>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static Uri SetQuery(this Uri uri, string key, int value)
       => SetQuery(uri, key, value.ToString());

    /// <summary>
    /// 设置地址的查询条件（“?”以后的）
    /// </summary>
    /// <param name="uri"></param>
    /// <param name="queryString">会把传入的字符串使用“?”分割（会移除空字串）以后使用最后的部分</param>
    /// <example>
    /// <![CDATA[
    /// uri.SetQuery("https://domain.com/path?a=1?b=2"); // 会使用“?b=2”
    /// ]]>
    /// </example>
    /// <returns></returns>
    public static Uri SetQuery(this Uri uri, string queryString) {
        var a = queryString.Split('?', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        var q = a.Length == 1 ? $"?{a[0]}" : $"?{a.Last()}";
        return new UriBuilder(uri) {
            Query = QueryString.FromUriComponent(q).ToString(),
        }.Uri;
    }

    #region QueryCollection SET QUERY
    /// <summary>
    /// 
    /// </summary>
    /// <param name="uri"></param>
    /// <returns></returns>
    public static QueryCollection GetQuery(this Uri uri) {
        var qs = QueryString.FromUriComponent(uri);
        var list = qs.HasValue
                    ? (qs.Value.StartsWith('?') ? qs.Value[1..] : qs.Value)
                            .Split("&")
                            .Select(s => s.Split("="))
                            .Select(a => a.Length > 1 ? [a[0], WebUtility.UrlDecode(a[1])] : a)
                            .ToArray()
                    : [];
        var qc = new Dictionary<string, StringValues>();
        foreach (var item in list) {
            var key = item[0];
            var value = item.Length > 1 ? item[1] : string.Empty;
            if (qc.ContainsKey(key) == false) {
                qc.Add(key, value);
            } else {
                qc[key] += value;
            }
        }
        return new QueryCollection(qc);
    }
    /// <summary>
    /// 设置地址的查询条件（“?”以后的）
    /// </summary>
    /// <param name="qc"></param>
    /// <param name="key">如果存在相同的 key 会覆盖</param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static QueryCollection SetQuery(this QueryCollection qc, string key, StringValues value) {
        var dict = qc.ToDictionary(k => k.Key, k => k.Value);
        if (!dict.TryAdd(key, value)) {
            dict[key] = value;
        }

        return new QueryCollection(dict);
    }
    /// <summary>
    /// 设置地址的查询条件（“?”以后的）
    /// </summary>
    /// <param name="qc"></param>
    /// <param name="query">如果存在相同的 key 会覆盖</param>
    /// <returns></returns>
    public static QueryCollection SetQuery(this QueryCollection qc, IEnumerable<KeyValuePair<string, string>> query) {
        foreach (var item in query) {
            qc = SetQuery(qc, item.Key, item.Value);
        }
        return qc;
    }
    #endregion
    #endregion
    /// <summary>
    /// 
    /// </summary>
    /// <param name="qs"></param>
    /// <param name="dict"></param>
    /// <returns></returns>
    public static QueryString AddQuery(this QueryString qs, IDictionary<string, string> dict) {
        var list = dict.Select(i => new KeyValuePair<string, string?>(i.Key, i.Value));
        qs += QueryString.Create(list);
        //dict.Keys.ForEach(key =>
        //    qs = AddQuery(qs, key, dict[key])
        //);
        return qs;
    }

    /// <summary>
    /// 编码传入的地址中的路径（PATH）部分
    /// <see cref="System.Web.HttpUtility.UrlEncode(string)"/>
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    public static string EncodePath(this string url) {
        if (Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out var uri) == false) return url;
        var path = uri.LocalPath.Split('/')
            .Select(pathPart => System.Web.HttpUtility.UrlPathEncode(pathPart).Split('+').JoinBy("%2b"))
            .JoinBy('/');
        var newUri = new UriBuilder(uri) {
            Port = IsDefaultPort(uri, out var _) ? -1 : uri.Port,
            Path = path,
        };
        return newUri.ToString();
    }
    /// <summary>
    /// 检查是否是默认端口
    /// 暂时只支持FPT、HTTP、HTTPS、NNTP
    /// </summary>
    /// <param name="uri"></param>
    /// <param name="defaultPort"></param>
    /// <returns></returns>
    public static bool IsDefaultPort(this Uri uri, out int defaultPort) {
        if (uri.Scheme == Uri.UriSchemeFtp) {
            defaultPort = 21;
            return 21 == uri.Port;
        }
        if (uri.Scheme == Uri.UriSchemeHttp) {
            defaultPort = 80;
            return 80 == uri.Port;
        }
        if (uri.Scheme == Uri.UriSchemeHttps) {
            defaultPort = 433;
            return 443 == uri.Port;
        }
        if (uri.Scheme == Uri.UriSchemeNntp) {
            defaultPort = 119;
            return 119 == uri.Port;
        }
        defaultPort = -1;
        return false;
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    public static Uri? ToUri(this string url) {
        if (Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out var uri)) {
            return uri;
        }
        return null;
    }
    /// <summary>
    /// 把输入参数<paramref name="uri"/>中的查询条件（“?”以后的）和片段（“#”以后的）去掉
    /// </summary>
    /// <param name="uri"></param>
    /// <returns></returns>
    public static Uri Prune(this Uri uri) {
        var builder = new UriBuilder(uri) {
            Query = string.Empty,
            Fragment = string.Empty
        };
        return builder.Uri;
    }
}
